package zld369504.tw.m_team.api;

import android.content.Context;
import android.support.annotation.NonNull;
import android.util.Log;

import com.jakewharton.picasso.OkHttp3Downloader;
import com.squareup.picasso.Picasso;

import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import io.reactivex.annotations.Nullable;
import okhttp3.Cache;
import okhttp3.Callback;
import okhttp3.Cookie;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import zld369504.tw.m_team.DatabaseHelper;
import zld369504.tw.m_team.LocalCookieStore;

public class MTeamHttpsApiImpl implements MTeamHttpsApi {
    public static final String baseUrl = "https://tp.m-team.cc";
    private static final String TAG = "MTeamHttpsApiImpl";
    private static final String userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36";
    private static MTeamHttpsApiImpl impl;
    private OkHttpClient client;
    private Context context;

    private MTeamHttpsApiImpl() {
    }

    public static final MTeamHttpsApiImpl getInstance() {
        if (impl == null) {
            impl = new MTeamHttpsApiImpl();
        }
        return impl;
    }

    @Override
    public void init(Context context) {
        this.context = context;
        File cacheFileDir = null;
        boolean externalCacheDirAvailable = true;
        cacheFileDir = context.getExternalCacheDir();
        if (cacheFileDir == null) {
            externalCacheDirAvailable = false;
            cacheFileDir = context.getCacheDir();
        }
        MyCookieJar jar = new MyCookieJar(context);
        OkHttpClient.Builder cb = new OkHttpClient.Builder();
        client = cb.followSslRedirects(false)
                .followRedirects(false)
                .cookieJar(jar)
                .addNetworkInterceptor(new LogInterceptor())
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(20, TimeUnit.SECONDS)
                .build();

        Picasso picasso = new Picasso.Builder(context)
                .downloader(new OkHttp3Downloader(new OkHttpClient.Builder()
                        .followSslRedirects(true)
                        .followRedirects(true)
                        .addNetworkInterceptor(new LogInterceptor())
                        .connectTimeout(10, TimeUnit.SECONDS)
                        .readTimeout(20, TimeUnit.SECONDS)
                        .cache(new Cache(cacheFileDir, externalCacheDirAvailable ? 400L * 1024L * 1024L : 200L * 1024L * 1024L))//400MB缓存...
                        .build()))
                .build();
        Picasso.setSingletonInstance(picasso);
    }

    @Override
    public void login(String username, String password, Callback callback) {
        RequestBody body = new FormBody.Builder()
                .add("username", username)
                .add("password", password).build();
        Request request = new Request.Builder().url(baseUrl + "/takelogin.php")
                .addHeader("Referer", baseUrl + "/login.php")
                .addHeader("Origin", baseUrl)
                .post(body)
                .build();
        client.newCall(request).enqueue(callback);
    }

    @Override
    public Response login(String username, String password) throws IOException {
        RequestBody body = new FormBody.Builder()
                .add("username", username)
                .add("password", password).build();
        Request request = new Request.Builder().url(baseUrl + "/takelogin.php")
                .addHeader("Referer", baseUrl + "/login.php")
                .addHeader("Origin", baseUrl)
                .post(body)
                .build();
        return client.newCall(request).execute();
    }

    @Override
    public void getMainPage(Callback callback) {
        //拿到登陆后操作的某个网页的内容
        Request redirectRequest = new Request.Builder().url(baseUrl + "/index.php")
                .build();
        client.newCall(redirectRequest).enqueue(callback);
    }

    @NonNull
    @Override
    public Response getMainPage() throws IOException {
        Request mainRequest = new Request.Builder().url(baseUrl + "/index.php")
                .build();
        return client.newCall(mainRequest).execute();
    }

    @Override
    public void getGeneralAdultMovieList(Callback callback) {
        Request redirectRequest = new Request.Builder().url(baseUrl + "/adult.php")
                .build();
        client.newCall(redirectRequest).enqueue(callback);
    }

    @Override
    public void getTorrentDetailInfo(int torrentId, Callback callback) {
        Request redirectRequest = new Request.Builder().url(baseUrl + "/details.php?id=" + String.valueOf(torrentId) + "&hit=1")
                .build();
        client.newCall(redirectRequest).enqueue(callback);
    }

    @Override
    public void getComprehensiveTorrentsList(Callback callback) {
        Request redirectRequest = new Request.Builder().url(baseUrl + "/torrents.php")
                .build();
        client.newCall(redirectRequest).enqueue(callback);
    }

    @Override
    public void getFourKList(Callback callback) {
        Request redirectRequest = new Request.Builder().url(baseUrl + "/torrents.php?standard6=1")
                .build();
        client.newCall(redirectRequest).enqueue(callback);
    }

    @Override
    public void getBookmarksTorrentList(int type, Callback callback) {
        String url;
        switch (type) {
            case 0:
                url = baseUrl + "/torrents.php?inclbookmarked=1&allsec=1&incldead=0";
                break;
            case 1:
                url = baseUrl + "/movie.php?inclbookmarked=1&allsec=1&incldead=0";
                break;
            case 2:
                url = baseUrl + "/adult.php?inclbookmarked=1&allsec=1&incldead=0";
                break;
            default:
                url = baseUrl + "/torrents.php?inclbookmarked=1&allsec=1&incldead=0";
                break;
        }
        Request redirectRequest = new Request.Builder().url(url)
                .build();
        client.newCall(redirectRequest).enqueue(callback);
    }

    @Override
    public OkHttpClient getClient() {
        return client;
    }

    @Override
    public @Nullable
    Response verify(String verifyUrl) throws IOException {
        Request verifyRequest = new Request.Builder().url(verifyUrl)
                .build();
        Response verifyResponse = client.newCall(verifyRequest).execute();
        if (verifyResponse.code() == 302) {
            //verify验证通过
            String realUrl = verifyResponse.header("Location");
            Request realRequest = new Request.Builder().url(realUrl)
                    .build();
            return client.newCall(realRequest).execute();
        } else {
            return null;
        }
    }

    @Override
    public Response getPersonalInformation(int userId) throws IOException {
        Request personalInfoRequest = new Request.Builder().url(baseUrl + "/userdetails.php?id=" + userId)
                .build();
        return client.newCall(personalInfoRequest).execute();
    }

    private class MyCookieJar implements okhttp3.CookieJar {

        private Context context;

        public MyCookieJar(Context context) {
            this.context = context;
        }

        @Override
        public void saveFromResponse(HttpUrl httpUrl, List<Cookie> list) {
            if (httpUrl.host().contains("m-team.cc")) {
                boolean fail = false;
                for (Cookie cookie : list) {
                    Log.d(TAG, "cookie::name=" + cookie.name());
                    Log.d(TAG, "cookie::value=" + cookie.value());
                    if (cookie.name().equals("flash_msg")) {
                        //无效cookie
                        fail = true;
                        break;
                    }
                }
                if (!fail) {
                    saveCookie(list);
                }
            }
        }

        @Override
        public List<Cookie> loadForRequest(HttpUrl httpUrl) {
            if (httpUrl.host().contains("m-team.cc"))
                return readCookie();
            else
                return new ArrayList<>();
        }

        private void saveCookie(List<Cookie> list) {
            DatabaseHelper db = DatabaseHelper.getHelper(context);
            try {
                db.getCookieDao().queryRaw("delete from tb_cookie");
                for (int i = 0; i < list.size(); i++) {
                    db.getCookieDao().create(LocalCookieStore.okhttpCookie2LocalCookieStore(list.get(i)));
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        private List<Cookie> readCookie() {
            DatabaseHelper db = DatabaseHelper.getHelper(context);
            List<Cookie> list = new ArrayList<>();
            try {
                List<LocalCookieStore> localCookieStoreList = db.getCookieDao().queryForAll();
                for (LocalCookieStore store : localCookieStoreList) {
                    list.add(LocalCookieStore.localCookieStore2OkhttpCookie(store));
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return list;
        }
    }

    private class LogInterceptor implements Interceptor {
        @Override
        public okhttp3.Response intercept(Chain chain) throws IOException {
            Request request = chain.request();

            Log.d(TAG, "request url:\n" + request.url().url().toString());
            Request newRequest = request.newBuilder()
                    .removeHeader("User-Agent")
                    .addHeader("Upgrade-Insecure-Requests", "1")
                    .addHeader("User-Agent", userAgent)
                    .addHeader("Accept-Language", "zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7,ja;q=0.6,ru;q=0.5").build();

            Log.d(TAG, "request header:\n" + newRequest.headers());

            long t1 = System.nanoTime();
//            okhttp3.Response response = chain.proceed(newRequest);
//            long t2 = System.nanoTime();
//
//            Log.d(TAG, String.format(Locale.getDefault(), "Received response for %s in %.1fms%n%s",
//                    response.request().url(), (t2 - t1) / 1e6d, response.headers()));
//
//            okhttp3.MediaType mediaType = response.body().contentType();
//            String content = response.body().string();
//
//            Log.d(TAG, "response body:\n" + content);
//            return response.newBuilder()
//                    .body(okhttp3.ResponseBody.create(mediaType, content))
//                    .build();
            return chain.proceed(newRequest);
        }
    }


}
